#ifndef THREADWRAPPER_H
#define THREADWRAPPER_H
/**
 * @file ThreadWrapper.h
 * @brief Header file for the ThreadWrapper class.
 * 
 * The ThreadWrapper.h file contains the declaration of the ThreadWrapper class, a utility class 
 * designed for enhanced thread management in C++ applications. The ThreadWrapper class extends 
 * the basic functionality provided by std::thread, offering additional features like thread naming, 
 * setting thread priority and affinity, and more effective management of thread lifecycle.
 *
 * This header is particularly useful for applications requiring advanced thread management, such 
 * as setting specific properties for threads or managing their lifecycle more precisely than what 
 * std::thread offers. It encapsulates the complexity of thread operations, making the process of 
 * creating and managing threads simpler and more intuitive for the developer.
 * 
 * The class ensures proper joining of threads on destruction, thus preventing potential issues 
 * with dangling threads. It also offers the flexibility to detach threads when automatic joining 
 * is not desired.
 * 
 * Example usage and further details are provided within the class documentation.
 *
 * @author liuzhiyu (liuzhiyu27@foxmail.com)
 * @copyright Copyright (c) 2023 by liuzhiyu, All Rights Reserved.
 */
#include <iostream>
#include <thread>
#include <mutex>
#include <string>
#include <functional>
#include <stdexcept>
#include <atomic>
#include <vector>
#include <queue>
#include "SoftWareVersion.h"

/**
 * @class ThreadWrapper
 * @brief A utility class for enhanced thread management.
 *
 * The ThreadWrapper class provides an encapsulated, more flexible, and easier-to-use interface 
 * for working with threads in C++. It extends the basic functionality of std::thread by providing 
 * additional capabilities like thread naming, setting thread priority and affinity, and managing 
 * thread lifecycle.
 *
 * This class is particularly useful in scenarios where threads need to be closely managed or 
 * configured beyond the capabilities of std::thread. For instance, in a multi-threaded application 
 * where thread identity (via naming) is crucial for debugging, or where threads are required to 
 * run on specific CPU cores for performance reasons.
 *
 * ThreadWrapper simplifies thread creation and management by allowing the user to define a thread's 
 * main function, start and stop the thread as needed, and set various thread properties, such as 
 * stack size, name, CPU affinity, and priority. It also provides a mechanism to block specific 
 * signals in a thread, enhancing control over thread behavior.
 *
 * Example usage:
 *     ThreadWrapper myThread;
 *     myThread.setmain([] { // thread function code });
 *     myThread.setName("MyThread");
 *     myThread.start();
 *     // Perform operations
 *     myThread.stop();
 *
 * @note The class ensures that the thread is properly joined on destruction, preventing 
 *       any potential for undefined behavior due to dangling threads. It also provides 
 *       methods to detach the thread if automatic joining is not desired.
 */
class ThreadWrapper {

public:
    /**
     * @brief Constructor for ThreadWrapper.
     *
     * Initializes the member variables.
     */
    ThreadWrapper() : m_thread_(), m_mainFuncWithStop(nullptr), m_name(""), m_isRunning(false), m_isDetaching(false), m_stopRequested(false) {}

    /**
     * @brief Destructor for ThreadWrapper.
     *
     * Joins the thread if it is joinable.
     */ 
    ~ThreadWrapper() = default; 

    /**
     * @brief Deleted copy constructor for ThreadWrapper.
     */

    ThreadWrapper(const ThreadWrapper&) = delete;
    ThreadWrapper& operator=(const ThreadWrapper&) = delete;

    /**
     * @brief set move constructor for ThreadWrapper.
     */ 
    ThreadWrapper(ThreadWrapper&&) = default;
    ThreadWrapper& operator=(ThreadWrapper&&) = default;    


    /**
     * @brief Starts the thread using m_mainFunc as the thread function.
     */
    void start();

    /**
     * @brief Stops the thread, blocking until the thread execution completes.
     */
    void stop(bool kill = false);

    /**
     * @brief Sets the thread to a detached state.
     *
     * A detached thread will automatically clean up its resources upon termination.
     */
    void detach();

    /**
     * @brief Get the thread stack size.
     * @param stackSize Size of the stack in bytes.
     */
    void getlimit(size_t &stackSize);

    /**
     * @brief Sets the main function of the thread.
     * @param func The function to be executed by the thread.
     */
    void setmain(std::function<void(const std::atomic<bool>&)> func);

    /**
     * @brief Sets the name of the thread.
     * @param name The name of the thread.
     */
    void setName(const std::string& name);

    /**
     * @brief Sets the CPU affinity for the thread.
     * @param cpus A vector of CPU cores to which the thread should be bound.
     */
    void setAffinity(const std::vector<int>& cpus);

    /**
     * @brief Sets the priority for the thread.
     * @param policy The scheduling policy (only used on non-Windows platforms).
     * @param priority The priority level to be set.
     * @throw std::runtime_error If the priority or policy values are invalid or setting fails.
     */
#ifdef _WIN32
    void setPriority(,int priority,int policy);
#else
    void setPriority(int priority,int policy = SCHED_OTHER);
#endif

    /**
     * @brief Sets the signal mask for the thread, blocking certain signals.
     * @param signals A list of signals to block.
     * @throw std::runtime_error If there is an issue setting the signal mask.
     */
    void setSignalMask(const std::vector<int>& signals);

    /**
     * @brief Checks if the thread has a main function set.
     * @return True if the thread has a main function set, false otherwise.
     */
    bool hasMain() const;
    /**
     * @brief Checks if the thread is currently running.
     * @return True if the thread is running, false otherwise.
     */
    bool isRunning() const;
    /**
     * @brief Checks if the thread is joinable.
     * @return True if the thread is joinable, false otherwise.
     */
    bool isJoinable() const;
    /**
     * @brief Checks if the thread is currently detaching.
     * @return True if the thread is detaching, false otherwise.
     */
    bool isDetaching() const;

private:
    std::thread m_thread_; ///< The underlying thread object.
    std::function<void(const std::atomic<bool>&)> m_mainFuncWithStop; ///< The main function to be executed by the thread, accepting a stop token.
    std::string m_name; ///< The name of the thread, useful for debugging and identification.
    std::atomic<bool> m_isRunning; ///< Flag to track if the thread is currently running.
    std::atomic<bool> m_isDetaching; ///< Flag to track if the thread is currently detaching.
    std::atomic<bool> m_stopRequested{false}; ///< Flag to signal the thread function to stop.
    std::queue<std::function<void()>> m_taskQueue;///< The task queue of the thread.
    mutable std::mutex m_queueMutex;///< The mutex of the task queue.
    mutable std::mutex m_startStopMutex; ///< The mutex used for thread start/stop operations.
    /**
     * @brief Retrieves the stack size limit of the thread.
     *
     * This method is used internally to get the current stack size limit for the thread.
     * It's useful for debugging and optimizing memory usage of the thread.
     *
     * @param stackSize Reference to a size_t variable where the stack size will be stored.
     */
    void _getlimit(size_t &stackSize);

    /**
     * @brief Sets the priority of the thread.
     *
     * This method is used internally to set the priority of the thread, which can be 
     * crucial for performance tuning in systems where thread priority is significant.
     *
     * @param policy The scheduling policy (used on non-Windows platforms).
     * @param priority The priority level to be set.
     */
    void _setPriority(int policy, int priority);

    /**
     * @brief Sets the CPU affinity of the thread.
     *
     * This method binds the thread to specific CPU cores, which can be important in
     * performance-sensitive applications where controlling which cores the thread runs on is required.
     *
     * @param cpus A vector of CPU core IDs to which the thread should be bound.
     */
    void _setAffinity(const std::vector<int>& cpus);

    /**
     * @brief Sets the name of the thread.
     *
     * This method is used internally for setting the name of the thread, which is helpful
     * for debugging and monitoring purposes.
     *
     * @param name The name to be assigned to the thread.
     */
    void _setName(const std::string& name);
    /**
     * @brief Processes the task queue of the thread.   
     * 
     * This method is used internally to process the task queue of the thread.  
     * It is used when the thread is running to execute the tasks in the queue.
     */
    void __processTasks(void);
    /**
     * @brief Executes the given function if the thread is currently running.
     *
     * This method is a utility function used internally to safely execute operations
     * only if the thread is in a running state, avoiding actions on a stopped or non-started thread.
     *
     * @param func The function to be executed.
     */
    void __executeIfRunning(std::function<void()> func);
};


#endif
